home *** CD-ROM | disk | FTP | other *** search
/ Garbo / Garbo.cdr / mac / hypercrd / xcmd / dxcmds34.sit / Dartmouth XCMD's 3.4.3 / card_4530.txt < prev    next >
Text File  |  1990-04-17  |  34KB  |  867 lines

  1. -- card: 4530 from stack: in.3
  2. -- bmap block id: 0
  3. -- flags: 4000
  4. -- background id: 3241
  5. -- name: PrintField
  6. ----- HyperTalk script -----
  7. on Install
  8.   put ChooseTargetStack() into stackName
  9.   InstallResource XCMD,PrintField,stackName
  10.   InstallResource DITL,PrintField,stackName
  11.   InstallResource DLOG,PrintField,stackName
  12. end Install
  13.  
  14.  
  15. -- part 1 (button)
  16. -- low flags: 00
  17. -- high flags: A003
  18. -- rect: left=52 top=300 right=322 bottom=221
  19. -- title width / last selected line: 0
  20. -- icon id / first selected line: 0 / 0
  21. -- text alignment: 1
  22. -- font id: 0
  23. -- text size: 12
  24. -- style flags: 0
  25. -- line height: 16
  26. -- part name: Print the Documentation
  27. ----- HyperTalk script -----
  28. on mouseUp
  29.   printfield "field 1",2
  30.   get the result
  31.   if it is not empty then put it
  32. end mouseUp
  33.  
  34.  
  35.  
  36. -- part 12 (field)
  37. -- low flags: 81
  38. -- high flags: 2007
  39. -- rect: left=12 top=26 right=298 bottom=491
  40. -- title width / last selected line: 0
  41. -- icon id / first selected line: 0 / 0
  42. -- text alignment: 0
  43. -- font id: 22
  44. -- text size: 10
  45. -- style flags: 0
  46. -- line height: 13
  47. -- part name: Source
  48.  
  49.  
  50. -- part 13 (button)
  51. -- low flags: 00
  52. -- high flags: A003
  53. -- rect: left=299 top=300 right=322 bottom=438
  54. -- title width / last selected line: 0
  55. -- icon id / first selected line: 0 / 0
  56. -- text alignment: 1
  57. -- font id: 0
  58. -- text size: 12
  59. -- style flags: 0
  60. -- line height: 16
  61. -- part name: Show Pascal Source
  62. ----- HyperTalk script -----
  63. on mouseUp
  64.   set the visible of card field 1 to not the visible of card field 1
  65.   if the visible of card field 1 is true then
  66.     set the name of me to "Hide Pascal Source"
  67.   else set the name of me to "Show Pascal Source"
  68. end mouseUp
  69.  
  70.  
  71.  
  72. -- part contents for background part 16
  73. ----- text -----
  74. PRINTFIELD XCMD version 1.5.1
  75. Kevin Calhoun
  76.  
  77. NOTE TO USERS OF EARLIER VERSIONS:  The parameter list of PrintField changed with version 1.4.  Please be sure to read "CHANGES FROM VERSIONS 1.0 AND 1.2" if you want to replace those earlier versions in your stacks.
  78.  
  79. The PrintField XCMD prints the text of a field in the field's current textFont, textSize, textStyle, textHeight, and width.  You may supply additional information about margins in order to place the text anywhere you like on the page.
  80.  
  81. PrintField uses a dialog box to inform the user that printing is in progress.  It passes to the printer driver the short name of the field to be printed as the document name.
  82.  
  83. In case of an error, PrintField returns an error message as the Result.  Word 1 of this message will be "Error".  If the user presses the cancel button in either of the print job dialog boxes, the Result will be "Cancel".
  84.  
  85. PrintField can print only one field at a time.  It works with both the LaserWriter and the ImageWriter.
  86.  
  87. CHANGES FROM VERSIONS 1.0 AND 1.2
  88. The parameter list changed with version 1.4 in order to accommodate users who wanted the option of skipping the Page Setup and Print Job dialog boxes.  A new parameter, called dialogCount, was added after the field designation and before the margin settings to specify which of the print dialog boxes the user sees.  If you used margin settings with earlier versions of PrintField, you will have to alter your scripts to accord with the new parameter list used by versions 1.4 and later.
  89.  
  90. INVOKING PRINTFIELD
  91.  
  92. PrintField "fieldDesignation",<dialogCount>,<leftMargin>,<rightMargin>,<topMargin>,    <bottomMargin>
  93.  
  94. Parameters given inside the brackets, such as  <notNeeded>,  are optional.
  95.  
  96. fieldDesignation:
  97. You may designate the field to print in any way considered valid by HyperCard, by number, id, or name, with one exception:  you can't use the field's name if it is more than one word.  If you do use the field's name, don't put the field name in quotation marks, because nested quotations confuse HyperCard.  (See the examples below.)
  98.  
  99. dialogCount:
  100. If dialogCount is 2 (or anything other than 0 or 1), then the user will see both the Page Setup and the Print Job dialog boxes before the printing process begins.  If dialogCount is 1, then the user will see only the Print Job dialog box.  If dialogCount is 0, then neither of these dialog boxes will appear before printing.  If you set dialogCount equal to 0 or 1, thereby suppressing one or both of the print dialogs, the default settings stored in the printer resource file will be used for the print job, just as if the user clicked "OK" without changing any of the settings in the dialog.
  101.  
  102. There is no way in this version to set such things as paper orientation or number of copies to values other than the defaults by any means other than the dialog boxes.  Moreover, PrintField is unable to access the settings the user designates by choosing Page Setup from HyperCard's File menu.  If you want to enable printing with settings other than the defaults, set dialogCount to 2.
  103.  
  104. Setting Margins:
  105. Values for leftMargin, rightMargin, topMargin, and bottomMargin are given in pixels.  According to QuickDraw, one pixel equals 1/72 inch; therefore you can specify a one inch margin by passing 72 as the margin parameter.  If you don't supply margin parameters, PrintField defaults to half-inch margins on the top, left, and bottom of the page, and prints each line of the text about as wide as it appears on the screen.
  106.  
  107. Valid Examples--
  108. 1.  PrintField "bkgnd field 1"                -- default values will be used for margins
  109. 2.  PrintField "bkgnd field 1",0,0,0,0,0     -- this will print as much as possible on a page
  110. 3.  PrintField "card field id 22",2,72,72,72,72     -- by id, with one inch margins all around
  111. 4.  PrintField "card field foo",2,72          -- by name, with a left margin one inch wide
  112.  
  113. See the script of the button "Print the Documentation" for another example.
  114.  
  115. It is possible to put the designation of the field into a variable and then pass the variable to PrintField, as followsΓǪ
  116.  
  117. on openField
  118.   if the optionKey is down then
  119.     put the name of the target into theName
  120.     put the id of the target into theField
  121.     if word 1 of theName is "card" then put "card field id " before theField
  122.     else put "field id " before theField
  123.     PrintField theField
  124.   end if
  125. end openField
  126.  
  127. This handler prints a field if the field is clicked while the option key is down. 
  128.  
  129. COPYING PRINTFIELD INTO YOUR STACKS
  130. Warning to ResEdit and ResCopy users:  PrintField requires a DLOG resource and a DITL resource as well as the XCMD resource--these resources are named "PrintField" and numbered 9140 (the same number as the PrintField XCMD) so you can find them easily.  If either the DITL or the DLOG resource is not present, PrintField will still print properly, and printing can still be canceled by pressing command-period, but the user won't have the benefit of the information the dialog provides.
  131.  
  132. THE COMMAND-PERIOD PROBLEM
  133. In early versions of HyperCard, when background printing was not enabled, the print job was not aborted properly when the user pressed command-period.  HyperCard intercepted command-period keypresses before the Print Manager saw them and interpreted them as the user's signal to abort the execution of the current script.  Therefore, the print job was aborted by HyperCard preventing PrintField from completing and exiting normally and not according to the proper method, which requires further communication with the Print Manager for the printer driver to clean up after itself.  A number of difficulties would arise as a result--when the current printer was a LaserWriter, its status dialog box was not removed from the screen, and on occasion the Macintosh would bomb.  This problem has gone away in HyperCard 1.2.2--command-period keypresses no longer interrupt XCMD's.
  134.  
  135. CHANGE HISTORY
  136. 3/7/88 1.0
  137. 3/17/88 1.1 -- Fixed erasure problem when printing on LaserWriter with a small lineHeight.
  138. 4/7/88 1.2 -- Dialog now centered on third party screens also.
  139. 6/8/88 1.4 -- Fixed problem printing multiple pages on ImageWriter.  Improved error handling to accord with changes in HyperCard 1.2.  Added option of skipping one or both print dialogs.  Improved WYSIWYG default margins (the width of the line on the page is much more often the same as it appears on the screen).  Fixed problem with last line of page when font ascent was small.
  140. 2/24/89 1.5 -- Altered source code for compatibility with MPW Pascal 3.0.  Added use of watch cursor, because Roger waved the interface guidelines at me.
  141. 3/15/89 1.5.1 -- Switched to trap-based printing manager.  PrintField now requires System 4.1 or later, which shouldn't be a hardship for HyperCard users.  Also, now returns "Cancel" as the result when user presses cancel button in either dialog.
  142.  
  143. NOTES FOR PROGRAMMERS:
  144. PrintField contains code for finding out about all the properties of a field.  You might find the functions GetFontOfField, GetJustOfField, etc., to be useful in your XCMD's.
  145.  
  146. -- part contents for card part 12
  147. ----- text -----
  148. UNIT PrintUnit;
  149.  
  150. { PrintField XCMD ┬⌐1988-1989 by the Trustees of Dartmouth College }
  151. { Written by Kevin Calhoun }
  152.  
  153. { This source compatible with MPW Pascal 3.0 }
  154.  
  155. (*
  156. Pascal PrintField.p
  157. Link -m ENTRYPOINT Γêé
  158.      -o "YourFile" Γêé
  159.      -rt XCMD=9140 Γêé
  160.      -sn Main=PrintField Γêé
  161.      PrintField.p.o Γêé
  162.     "{Libraries}"interface.o Γêé
  163.     "{PLibraries}"Paslib.o Γêé
  164.     "{Libraries}"HyperXLib.o
  165. *)
  166.  
  167. {$R-}
  168.  
  169. INTERFACE
  170.  
  171.   USES
  172.     Types,
  173.     Memory,
  174.     QuickDraw,
  175.     OSEvents,
  176.     Desk,
  177.     ToolUtils,
  178.     Dialogs,
  179.     Resources,
  180.     Fonts,
  181.     PrintTraps,
  182.     HyperXCmd;
  183.  
  184.   CONST
  185.     idledlg = 9140;
  186.     marginDefault = 36;
  187.     throwAway = 5;
  188.     scrollWidth = 18;
  189.     wideExtra = 4;
  190.     ourMask = everyEvent - keyDownMask - keyUpMask;
  191.  
  192.   PROCEDURE EntryPoint (paramPtr : XCmdPtr);
  193.  
  194. IMPLEMENTATION
  195.  
  196.   PROCEDURE PrintField (paramPtr : XCmdPtr); FORWARD;
  197.  
  198.   PROCEDURE EntryPoint(paramPtr: XCMDPtr);
  199.   BEGIN
  200.     PrintField(paramPtr);
  201.   END;
  202.  
  203.   PROCEDURE myStdRect (verb : GrafVerb;
  204.                   r : rect);
  205. { This procedure will replace the StdRect QuickDraw bottleneck procedure }
  206. { when we go into our printing loop.  We use TEUpdate to draw text, and }
  207. { TEUpdate calls EraseRect to clear the way before it draws anything. }
  208. { On a blank sheet of paper, there's no need to erase, so we replace the }
  209. { QuickDraw bottleneck that handles rectangles with a "do-nothing" procedure. }
  210. { This has two advantages when printing on the LaserWriter:  }
  211. {    1) Printing becomes faster, and  }
  212. {    2) A problem is avoided--the rectangles erased sometimes included the }
  213. { descenders of lines of text already drawn.  This happened with PrintField 1.0, }
  214. { which produced lines of text that were cut off at the bottom when the lineHeight }
  215. { of the field was smaller than about 4/3 of the average character height. }
  216.   BEGIN
  217.   END;
  218.   
  219.   FUNCTION GetScreenBitsBounds: Rect;
  220.   { get screenbits.bounds from the QuickDraw globals }
  221.   TYPE
  222.     LongwordPtr = ^LONGINT;
  223.     BitMapPtr = ^BitMap;
  224.   CONST
  225.     screenBitsOffset = -122;
  226.     CurrentA5 = $904;
  227.   VAR
  228.     screenBitsPtr : BitMapPtr;
  229.     myLongwordPtr : LongwordPtr;
  230.   BEGIN
  231.     myLongwordPtr := LongwordPtr(CurrentA5);
  232.       { myLongwordPtr now points to the pointer to the first QD global }
  233.     myLongwordPtr := LongwordPtr(myLongwordPtr^);
  234.       { myLongwordPtr now points to the first QD global }
  235.     screenBitsPtr := BitMapPtr(myLongwordPtr^ + screenBitsOffset);
  236.       { screenBitsPtr now points to the screenBits BitMap }
  237.     GetScreenBitsBounds := screenBitsPtr^.bounds;
  238.   END;
  239.  
  240.   FUNCTION GetField (paramPtr : XCmdPtr;
  241.                   whichField : Str255;
  242.                   VAR theHandle : Handle) : OSErr;
  243. { Given a valid designation of a field--by name, id, or number, }
  244. { returns the text of the field in a handle. }
  245. { We go through all of this to make sure we're printing the contents of }
  246. { a real field, and not just of an ordinary container, because later we'll }
  247. { be using field properties--lineHeight and so on--in order to format our output. }
  248.     VAR
  249.       theString : Str255;
  250.       cardFieldFlag : BOOLEAN;
  251.       matchPtr : Ptr;
  252.       theResult : Handle;
  253.       fieldID : INTEGER;
  254.   BEGIN
  255.     theResult := EvalExpr(paramPtr, CONCAT('the long name of ', whichField));
  256.    { if HC can get the long name of the object designated by whichField, it's a valid object }
  257.     IF (theResult <> NIL) AND (paramPtr^.result = noErr) THEN
  258.       BEGIN
  259.         MoveHHi(theResult);
  260.         HLock(theResult);
  261.         matchPtr := StringMatch(paramPtr, 'field', theResult^);
  262.    { if the long name of the object contains the word "field," then it's a field }
  263.         IF matchPtr <> NIL THEN
  264.           BEGIN
  265.             matchPtr := StringMatch(paramPtr, 'card field', theResult^);
  266.    { we want to know if it's a card or background field in order }
  267.    { to set the cardFieldFlag for GetFieldbyID, below }
  268.             cardFieldFlag := (matchPtr <> NIL);
  269.             DisposHandle(theResult);
  270.             theResult := EvalExpr(paramPtr, CONCAT('the id of ', whichField));
  271.    { we get the id of the field so that we can call GetFieldbyID }
  272.             IF (theResult <> NIL) AND (paramPtr^.result = noErr) THEN
  273.               BEGIN
  274.                 MoveHHi(theResult);
  275.                 HLock(theResult);
  276.                 ZeroToPas(paramPtr, theResult^, theString);
  277.                 fieldID := StrToNum(paramPtr, theString);
  278.                 DisposHandle(theResult);
  279.                 theResult := GetFieldByID(paramPtr, cardFieldFlag, fieldID);  { get the text }
  280.               END;  { if theResult <> nil when asking for the id of the field }
  281.           END  { if "field" is part of the long name of the object }
  282.         ELSE
  283.           BEGIN
  284.             DisposHandle(theResult);
  285.             theResult := NIL;
  286.           END;
  287.       END;  { if theResult <> nil when asking for the long name of the object }
  288.     theHandle := theResult;
  289.     GetField := paramPtr^.result;
  290.   END;  { function GetField }
  291.  
  292.   FUNCTION GetRectOfField (paramPtr : XCmdPtr;
  293.                   whichField : Str255) : Rect;
  294.     VAR
  295.       theRect : rect;
  296.  
  297.     FUNCTION GetRectItem (theItem : INTEGER) : INTEGER;
  298.       VAR
  299.         theResult : Handle;
  300.         s: Str255;
  301.         rectItemStr : Str255;
  302.     BEGIN
  303.       NumToStr(paramPtr, theItem, s);
  304.       theResult := EvalExpr(paramPtr, CONCAT('item ', s, ' of the rect of ', whichField));
  305.       IF theResult <> NIL THEN
  306.         BEGIN
  307.           ZeroToPas(paramPtr, theResult^, rectItemStr);
  308.           DisposHandle(theResult);
  309.           GetRectItem := StrToNum(paramPtr, rectItemStr);
  310.         END
  311.       ELSE
  312.         GetRectItem := 0;
  313.     END;
  314.  
  315.   BEGIN
  316.     theRect.left := GetRectItem(1);
  317.     theRect.top := GetRectItem(2);
  318.     theRect.right := GetRectItem(3);
  319.     theRect.bottom := GetRectItem(4);
  320.  
  321.     GetRectOfField := theRect;
  322.   END;
  323.  
  324.   FUNCTION GetJustOfField (paramPtr : XCmdPtr;
  325.                   whichField : Str255) : INTEGER;
  326.     VAR
  327.       theResult : Handle;
  328.       textAlign : INTEGER;
  329.       theStr : Str255;
  330.   BEGIN
  331.     theResult := EvalExpr(paramPtr, CONCAT('the textAlign of ', whichField));
  332.     ZeroToPas(paramPtr, theResult^, theStr);
  333.     DisposHandle(theResult);
  334.  
  335.     IF theStr = 'left' THEN
  336.       textAlign := teJustLeft
  337.     ELSE IF theStr = 'center' THEN
  338.       textAlign := teJustCenter
  339.     ELSE IF theStr = 'right' THEN
  340.       textAlign := teJustRight
  341.     ELSE
  342.       textAlign := teJustLeft;
  343.  
  344.     GetJustOfField := textAlign;
  345.   END;
  346.  
  347.   FUNCTION GetFontOfField (paramPtr : XCmdPtr;
  348.                   whichField : Str255) : INTEGER;
  349.     VAR
  350.       theResult : Handle;
  351.       fontNumber : INTEGER;
  352.       fontName : Str255;
  353.   BEGIN
  354.     theResult := EvalExpr(paramPtr, CONCAT('the textFont of ', whichField));
  355.     ZeroToPas(paramPtr, theResult^, fontName);
  356.     DisposHandle(theResult);
  357.  
  358.     GetFNum(fontName, fontNumber);
  359.     GetFontOfField := fontNumber;
  360.   END;
  361.  
  362.   FUNCTION GetTextSizeOfField (paramPtr : XCmdPtr;
  363.                   whichField : Str255) : INTEGER;
  364.     VAR
  365.       theResult : Handle;
  366.       theSize : INTEGER;
  367.       sizeStr : Str255;
  368.   BEGIN
  369.     theResult := EvalExpr(paramPtr, CONCAT('the textSize of ', whichField));
  370.     ZeroToPas(paramPtr, theResult^, sizeStr);
  371.     DisposHandle(theResult);
  372.  
  373.     theSize := StrToNum(paramPtr, sizeStr);
  374.     GetTextSizeOfField := theSize;
  375.   END;
  376.  
  377.   FUNCTION GetLineHeightOfField (paramPtr : XCmdPtr;
  378.                   whichField : Str255) : INTEGER;
  379.     VAR
  380.       theResult : Handle;
  381.       theLineHeight : INTEGER;
  382.       heightStr : Str255;
  383.   BEGIN
  384.     theResult := EvalExpr(paramPtr, CONCAT('the textHeight of ', whichField));
  385.     ZeroToPas(paramPtr, theResult^, heightStr);
  386.     DisposHandle(theResult);
  387.  
  388.     theLineHeight := StrToNum(paramPtr, heightStr);
  389.     GetLineHeightOfField := theLineHeight;
  390.   END;
  391.  
  392.   PROCEDURE AdjustForScrBarsAndWdMargins (paramPtr : XCmdPtr;
  393.                   whichField : Str255;
  394.                   VAR theRect : rect);
  395. { Given the rect of a field, adjusts the rectangle to make it the smallest }
  396. { rectangle containing the text of the field visible on the screen }
  397.     VAR
  398.       theResult : Handle;
  399.       theLineHeight : INTEGER;
  400.       theStr : Str255;
  401.   BEGIN
  402. { if the field has wide margins, we shrink the rectangle by wideExtra pixels all around }
  403.     theResult := EvalExpr(paramPtr, CONCAT('the wideMargins of ', whichField));
  404.     ZeroToPas(paramPtr, theResult^, theStr);
  405.     DisposHandle(theResult);
  406.     IF theStr = 'true' THEN
  407.       InsetRect(theRect, wideExtra, 0);
  408.  
  409. { if it's a scrolling field, we subtract scrollWidth from the right coordinate of the rect }
  410.     theResult := EvalExpr(paramPtr, CONCAT('the style of ', whichField));
  411.     ZeroToPas(paramPtr, theResult^, theStr);
  412.     DisposHandle(theResult);
  413.     IF theStr = 'scrolling' THEN
  414.       WITH theRect DO
  415.         right := right - scrollWidth;
  416.   END;
  417.  
  418.   FUNCTION GetTextStyleOfField (paramPtr : XCmdPtr;
  419.                   whichField : Str255) : Style;
  420.     VAR
  421.       theTextStyle : Handle;
  422.       thePtr : Ptr;
  423.       theStyle : Style;
  424.  
  425.     FUNCTION StyleIs (textStyle : handle;
  426.                     aStyle : Str255) : BOOLEAN;
  427.       VAR
  428.         thePtr : Ptr;
  429.     BEGIN
  430.       thePtr := StringMatch(paramPtr, aStyle, textStyle^);
  431.       IF thePtr <> NIL THEN
  432.         StyleIs := TRUE
  433.       ELSE
  434.         StyleIs := FALSE;
  435.     END;
  436.  
  437.   BEGIN
  438.     theStyle := [];
  439.  
  440.     theTextStyle := EvalExpr(paramPtr, CONCAT('the textStyle of ', whichField));
  441.     IF theTextStyle <> NIL THEN
  442.       BEGIN
  443.         IF StyleIs(theTextStyle, 'bold') THEN
  444.           theStyle := theStyle + [bold];
  445.  
  446.         IF StyleIs(theTextStyle, 'italic') THEN
  447.           theStyle := theStyle + [italic];
  448.  
  449.         IF StyleIs(theTextStyle, 'underline') THEN
  450.           theStyle := theStyle + [underline];
  451.  
  452.         IF StyleIs(theTextStyle, 'outline') THEN
  453.           theStyle := theStyle + [outline];
  454.  
  455.         IF StyleIs(theTextStyle, 'shadow') THEN
  456.           theStyle := theStyle + [shadow];
  457.  
  458.         IF StyleIs(theTextStyle, 'condense') THEN
  459.           theStyle := theStyle + [condense];
  460.  
  461.         IF StyleIs(theTextStyle, 'extend') THEN
  462.           theStyle := theStyle + [extend];
  463.  
  464.         DisposHandle(theTextStyle);
  465.       END;
  466.     GetTextStyleOfField := theStyle;
  467.   END;
  468.  
  469.   PROCEDURE PrintField (paramPtr : XCmdPtr);
  470.     VAR
  471.       currentPort : grafPtr;
  472.       myDlgPtr : DialogPtr;
  473.       myDITL, myDLOG : Handle;
  474.       dlogOK, goAhead : BOOLEAN;
  475.       prRecHdl : THPrint;
  476.       myStRec : TPrStatus;
  477.       myPrPort : TPPrPort;
  478.       theText : Handle;
  479.       hTE : TEHandle;
  480.       length : longint;
  481.       theTextStyle : Style;
  482.       theTextFont, theTextSize, theTextHeight, just : INTEGER;
  483.       FontIRec : FontInfo;
  484.       fieldName, str : Str255;
  485.       fieldRect, destRect, viewRect : rect;
  486.       fieldWidth, pageHeight, numLines, numCopies, myPgCount : INTEGER;
  487.       parameterCount, leftMargin, rightMargin, topMargin, bottomMargin : INTEGER;
  488.       dialogCount : LONGINT;
  489.       err : OSErr;
  490.       goToThisCard : Str255;
  491.       curs: CursHandle;
  492.  
  493.     PROCEDURE Fail (errMsg : Str255); { set theResult and quit }
  494.     BEGIN
  495.       paramPtr^.returnValue := PasToZero(paramPtr, errMsg);
  496.     END;
  497.  
  498.     FUNCTION GetDialog: BOOLEAN; { check to see if DLOG and DITL are present; }
  499.     VAR                                     { if so, put up the dialog }
  500.       dlogPresent : BOOLEAN;
  501.     BEGIN
  502.       dlogPresent := FALSE;
  503.       myDLOG := GetResource('DLOG', idledlg);
  504.       IF (myDLOG <> NIL) AND (ResError = noErr) THEN
  505.         BEGIN
  506.           myDITL := GetResource('DITL', idledlg);
  507.           dlogPresent := (myDITL <> NIL) AND (ResError = noErr);
  508.           IF dlogPresent THEN
  509.             myDlgPtr := GetNewDialog(idledlg, NIL, NIL);
  510.         END;
  511.       GetDialog := dlogPresent;
  512.     END;
  513.  
  514.     PROCEDURE ShowDialog;
  515. { Here we mess with the appearance of the dialog.  We center it on the screen, }
  516. { and also center the text items within the dialog. }
  517. { Also, we grab the document name and make it the window title, so that the }
  518. { printer driver can access that information -- see Tech Note #72. }
  519.       VAR
  520.         mainScreenRect, dlogRect : rect;
  521.         hGlobal : INTEGER;
  522.         theDialogTHndl : DialogTHndl;
  523.         wMgrPort : GrafPtr;
  524.         wTitle : Str255;
  525.         theResult : Handle;
  526.  
  527.       PROCEDURE CenterTextItem (theDialogPtr : DialogPtr;
  528.                       itemNo : INTEGER);
  529.         VAR
  530.           savePort : grafPtr;
  531.           item : handle;
  532.           itemType : INTEGER;
  533.           dlogRect, itemBox : Rect;
  534.           theStr : Str255;
  535.           width, textLeft : INTEGER;
  536.       BEGIN
  537.         GetDItem(theDialogPtr, itemNo, itemType, item, itemBox);
  538.         IF item <> NIL THEN
  539.           IF (itemType = statText) OR (itemType = statText + itemDisable) THEN
  540.             BEGIN
  541.               GetPort(savePort);
  542.               SetPort(theDialogPtr);
  543.               GetIText(item, theStr);
  544.               width := StringWidth(theStr) + 6;
  545.               IF itemNo = 1 THEN  { kludge for getting the width of an item that includes paramText }
  546.                 width := width - StringWidth('^0') + StringWidth(wTitle);
  547.               dlogRect := theDialogPtr^.portRect;
  548.               WITH dlogRect DO
  549.                 textLeft := (right - left - width) DIV 2;
  550.               WITH itemBox DO
  551.                 BEGIN
  552.                   left := textLeft;
  553.                   right := textLeft + width;
  554.                 END;
  555.               SetDItem(theDialogPtr, itemNo, itemType, item, itemBox);
  556.               SetPort(savePort);
  557.             END;
  558.       END;
  559.  
  560.     BEGIN
  561.       IF dlogOK THEN
  562.         BEGIN
  563.           theResult := EvalExpr(paramPtr, CONCAT('the short name of ', fieldName));
  564.           IF theResult <> NIL THEN
  565.             BEGIN
  566.               ZeroToPas(paramPtr, theResult^, wTitle);
  567.               DisposHandle(theResult);
  568.             END
  569.           ELSE
  570.             wTitle := fieldName;
  571.           SetWTitle(myDlgPtr, wTitle);
  572.           ParamText(wTitle, '', '', '');
  573.           CenterTextItem(myDlgPtr, 1);
  574.           CenterTextItem(myDlgPtr, 2);
  575.           myDLOG := GetResource('DLOG', idledlg);
  576.           theDialogTHndl := DialogTHndl(myDLOG);
  577. { we get the rect of the dialog directly from its DLOG resource in memory }
  578.           dlogRect := theDialogTHndl^^.boundsRect;
  579.           mainScreenRect := GetScreenBitsBounds;
  580.           WITH mainScreenRect DO
  581.             hGlobal := right - left;
  582.           WITH dlogRect DO
  583.             BEGIN
  584.               hGlobal := (hGlobal - (right - left)) DIV 2;
  585.               MoveWindow(myDlgPtr, hGlobal, top, FALSE);
  586.             END;
  587.           ShowWindow(myDlgPtr);
  588.           BringToFront(myDlgPtr);
  589.           DrawDialog(myDlgPtr);
  590.         END;
  591.     END;
  592.  
  593.     PROCEDURE SetDefaults;
  594.     BEGIN
  595.       viewRect := prRecHdl^^.prInfo.rPage;
  596.       topMargin := marginDefault;
  597.       bottomMargin := marginDefault;
  598.       leftMargin := marginDefault;
  599.       fieldRect := GetRectOfField(paramPtr, fieldName);
  600.       AdjustForScrBarsAndWdMargins(paramPtr, fieldName, fieldRect);
  601.       WITH fieldRect DO
  602.         fieldWidth := right - left - throwAway;
  603.     END;
  604.  
  605.     PROCEDURE GetDialogCount;
  606.     BEGIN
  607.       IF parameterCount > 1 THEN
  608.         BEGIN
  609.           ZeroToPas(paramPtr, paramPtr^.params[2]^, str);
  610.           dialogCount := StrToNum(paramPtr, str);
  611.         END  { if parameterCount > 1 }
  612.       ELSE
  613.         dialogCount := 2;
  614.     END;
  615.  
  616.     PROCEDURE GetMarginSettings;
  617.       VAR
  618.         theBottom : INTEGER;
  619.     BEGIN
  620.       IF parameterCount > 2 THEN
  621.         BEGIN
  622.           ZeroToPas(paramPtr, paramPtr^.params[3]^, str);
  623.           leftMargin := StrToNum(paramPtr, str);
  624.           IF leftMargin < 0 THEN
  625.             leftMargin := marginDefault;
  626.           IF parameterCount > 3 THEN
  627.             BEGIN
  628.               ZeroToPas(paramPtr, paramPtr^.params[4]^, str);
  629.               rightMargin := StrToNum(paramPtr, str);
  630.               IF rightMargin >= 0 THEN
  631.                 BEGIN
  632.                   WITH viewRect DO
  633.                     fieldWidth := right - left - leftMargin - rightMargin;
  634.                   IF fieldWidth < 10 THEN
  635.                     fieldWidth := 10;
  636.                 END;
  637.               IF parameterCount > 4 THEN
  638.                 BEGIN
  639.                   ZeroToPas(paramPtr, paramPtr^.params[5]^, str);
  640.                   topMargin := StrToNum(paramPtr, str);
  641.                   IF topMargin < 0 THEN
  642.                     topMargin := marginDefault;
  643.                   IF parameterCount > 5 THEN
  644.                     BEGIN
  645.                       ZeroToPas(paramPtr, paramPtr^.params[6]^, str);
  646.                       bottomMargin := StrToNum(paramPtr, str);
  647.                       IF bottomMargin < 0 THEN
  648.                         bottomMargin := marginDefault;
  649.                     END;  { if parameterCount > 5 }
  650.                 END;  { if parameterCount > 4 }
  651.             END;  { if parameterCount > 3 }
  652.         END;  { if parameterCount > 2 }
  653.       WITH viewRect DO
  654.         BEGIN
  655.           left := leftMargin;
  656.           top := topMargin;
  657.           right := leftMargin + fieldWidth;
  658.           bottom := bottom - bottomMargin;
  659.           IF bottom < top THEN
  660.             bottom := top + 10
  661.         END;
  662.     END;
  663.  
  664.     PROCEDURE GetFieldInfo;
  665.     BEGIN
  666.       just := GetJustOfField(paramPtr, fieldName);
  667.       theTextFont := GetFontOfField(paramPtr, fieldName);
  668.       theTextStyle := GetTextStyleOfField(paramPtr, fieldName);
  669.       theTextSize := GetTextSizeOfField(paramPtr, fieldName);
  670.       theTextHeight := GetLineHeightOfField(paramPtr, fieldName);
  671.     END;
  672.  
  673.     PROCEDURE SetPPortInfo;
  674.     BEGIN
  675.       TextFont(theTextFont);
  676.       TextFace(theTextStyle);
  677.       TextSize(theTextSize);
  678.       myPrPort^.gPort.txMode := srcOr;
  679.     END;
  680.  
  681.     PROCEDURE AdjustViewRect;
  682.     BEGIN
  683. { This will have to be modified if HyperCard ever uses the new Text Edit. }
  684.       WITH viewRect DO
  685.         pageheight := bottom - top;
  686.       numlines := pageheight DIV theTextHeight;
  687.       IF numlines < 1 THEN
  688.         numlines := 1;
  689.       pageheight := numlines * theTextHeight;
  690.       WITH viewRect DO
  691.         bottom := top + pageheight;
  692.       GetFontInfo(FontIRec);
  693.       destRect := viewRect;
  694.       destRect.bottom := 32767;
  695.     END;
  696.  
  697.     PROCEDURE GetPageCount;
  698. { This will have to be modified if HyperCard ever uses the new Text Edit. }
  699.     BEGIN
  700.       WITH hTE^^ DO
  701.         BEGIN
  702.           myPgCount := nLines DIV numlines;
  703.           IF (nLines MOD numlines) <> 0 THEN
  704.             myPgCount := myPgCount + 1;
  705.         END;
  706.     END;
  707.  
  708.     PROCEDURE SetTERec;
  709.     BEGIN
  710.       MoveHHi(theText);
  711.       HLock(theText);
  712.       length := StringLength(paramPtr, theText^);
  713.       TESetText(theText^, length, hTE);
  714.       DisposHandle(theText);
  715.       TESetJust(just, hTE);
  716.       WITH hTE^^ DO
  717.         BEGIN
  718.           txFont := theTextFont;
  719.           txFace := theTextStyle;
  720.           txSize := theTextSize;
  721.           fontAscent := theTextHeight - FontIRec.descent - FontIRec.leading;
  722.           lineHeight := theTextHeight;
  723.           crOnly := 1;
  724.           inPort := grafPtr(myPrPort);
  725.         END;
  726.     END;
  727.  
  728.     PROCEDURE PrintLoop;
  729.       VAR
  730.         copies, pg : INTEGER;
  731.     BEGIN
  732.       IF prRecHdl^^.prJob.bJDocLoop = bSpoolLoop THEN
  733.         numCopies := 1
  734.       ELSE
  735.         numCopies := prRecHdl^^.prJob.iCopies;
  736.       FOR copies := 1 TO numCopies DO
  737.         BEGIN
  738.           FOR pg := 1 TO myPgCount DO
  739.             BEGIN
  740.               PrOpenPage(myPrPort, NIL);
  741.               myPrPort^.gPort.grafProcs^.rectProc := @myStdRect;
  742. { It turned out that setting the bottlenecks any earlier didn't work -- }
  743. { PrOpenPage set them back to the postscript generating procedures. }
  744.               IF PrError = noErr THEN
  745.                 TEUpdate(viewRect, hTE);
  746.               PrClosePage(myPrPort);
  747.               OffsetRect(hTE^^.destRect, 0, -pageHeight);
  748.             END;  { for pg := 1 to myPgCount }
  749.         END;  { for copies := 1 to numCopies }
  750.       PrCloseDoc(myPrPort);
  751.       IF (prRecHdl^^.prJob.bJDocLoop = bSpoolLoop) AND (PrError = noErr) THEN
  752.         PrPicFile(prRecHdl, NIL, NIL, NIL, myStRec);
  753.     END;
  754.     
  755.     PROCEDURE UserCancel;
  756.     BEGIN
  757.       Fail('Cancel');
  758.     END;
  759.     
  760.   BEGIN  { procedure PrintField }
  761.     parameterCount := paramPtr^.paramCount;
  762.     IF parameterCount > 0 THEN
  763.       BEGIN
  764.         InitCursor;
  765.         goToThisCard := 'go to this card';
  766.         dlogOK := GetDialog;
  767.         ZeroToPas(paramPtr, paramPtr^.params[1]^, fieldName);
  768.         err := GetField(paramPtr, fieldName, theText);
  769.         IF (theText <> NIL) AND (err = noErr) THEN
  770.           BEGIN
  771.             HNoPurge(theText);
  772.             GetPort(currentPort);
  773.             PrOpen;
  774.             IF PrError = noErr THEN
  775.               BEGIN
  776.                 prRecHdl := THPrint(NewHandle(SIZEOF(TPrint)));
  777.                 IF (MemError = noErr) AND (prRecHdl <> NIL) THEN
  778.                   BEGIN
  779.                     PrintDefault(prRecHdl);
  780.                     IF PrError = noErr THEN
  781.                       BEGIN
  782.                         GetDialogCount;
  783.                         IF dialogCount IN [0, 1] THEN
  784.                           goAhead := TRUE
  785.                         ELSE
  786.                           BEGIN
  787.                             goAhead := PrStlDialog(prRecHdl);
  788.                             SendCardMessage(paramPtr, goToThisCard);
  789.                           END;
  790.                         IF goAhead THEN
  791.                           BEGIN
  792.                             IF dialogCount = 0 THEN
  793.                               goAhead := TRUE
  794.                             ELSE
  795.                               BEGIN
  796.                                 goAhead := PrJobDialog(prRecHdl);
  797.                                 SendCardMessage(paramPtr, goToThisCard);
  798.                               END;
  799.                             IF goAhead THEN
  800.                               BEGIN
  801.                                 ShowDialog;
  802.                                 IF PrValidate(prRecHdl) THEN
  803.                                   ; { we call PrValidate here only to give the printer driver }
  804.                                     { a chance to grab our document name -- see TN #72 }
  805.                                 curs := GetCursor(watchCursor);
  806.                                 SetCursor(curs^^);
  807.                                 myPrPort := PrOpenDoc(prRecHdl, NIL, NIL);
  808.                                 IF PrError = noErr THEN
  809.                                   BEGIN
  810.                                     SetDefaults;
  811.                                     GetMarginSettings;
  812.                                     GetFieldInfo;
  813.                                     SetPPortInfo;
  814.                                     AdjustViewRect;
  815.                                     hTE := TENew(destRect, viewRect);
  816.                                     IF hTE <> NIL THEN
  817.                                       BEGIN
  818.                                         SetTERec;
  819.                                         GetPageCount;
  820.                                         PrintLoop;
  821.                                         TEDispose(hTE);
  822.                                       END  { if we could create new TEHandle }
  823.                                     ELSE
  824.                                       BEGIN
  825.                                         PrCloseDoc(myPrPort);
  826.                                         IF GetHandleSize(theText) > 0 THEN
  827.                                           DisposHandle(theText);
  828.                                         IF MemError <> noErr THEN
  829.                                           BEGIN
  830.                                           NumToStr(paramPtr, MemError, str);
  831.                                           Fail(CONCAT('Error ', str));
  832.                                           END;
  833.                                       END;
  834.                                   END
  835.                                 ELSE
  836.                                   PrCloseDoc(myPrPort);
  837.                                 InitCursor;
  838.                               END  { if user confirms job dialog }
  839.                           ELSE UserCancel;
  840.                           END  { if user confirms style dialog }
  841.                       ELSE UserCancel;
  842.                       END;  { if PrintDefault worked OK }
  843.                     DisposHandle(Handle(prRecHdl));
  844.                   END;  { if MemError = noErr when allocating print record }
  845.                 PrClose;
  846.               END;  { if PrError = noErr when opening print driver }
  847.             IF PrError <> noErr THEN
  848.               BEGIN
  849.               NumToStr(paramPtr, PrError, str);
  850.               Fail(CONCAT('Error ', str))
  851.               END
  852.             ELSE IF MemError <> noErr THEN
  853.               BEGIN
  854.               NumToStr(paramPtr, MemError, str);
  855.               Fail(CONCAT('Error ', str));
  856.               END;
  857.             SetPort(currentPort);
  858.           END  { if theText <> nil }
  859.         ELSE
  860.           Fail(CONCAT('Error -- never heard of ', fieldName));
  861.         IF dlogOK THEN DisposDialog(myDlgPtr);
  862.       END  { if we have at least 1 parameter }
  863.     ELSE
  864.       Fail('PrintField XCMD 1.5.1, 15 March 1989, ┬⌐1988-1989 Dartmouth College');
  865.   END;  { procedure PrintField }
  866.  
  867. END.